﻿using System;
using System.Collections;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.Geometries
{
	[Serializable]
	public class GeometryCollection : Geometry, IGeometryCollection, IGeometry, ICloneable, IComparable, IComparable<IGeometry>, IEquatable<IGeometry>, IEnumerable<IGeometry>, IEnumerable
	{
		public GeometryCollection(IGeometry[] geometries) : this(geometries, Geometry.DefaultFactory)
		{
		}

		public GeometryCollection(IGeometry[] geometries, IGeometryFactory factory) : base(factory)
		{
			if (geometries == null)
			{
				geometries = new IGeometry[0];
			}
			if (Geometry.HasNullElements(CollectionUtil.Cast<IGeometry, object>(geometries)))
			{
				throw new ArgumentException("geometries must not contain null elements");
			}
			this._geometries = geometries;
		}

		public override Coordinate Coordinate
		{
			get
			{
				if (this.IsEmpty)
				{
					return null;
				}
				return this._geometries[0].Coordinate;
			}
		}

		public override Coordinate[] Coordinates
		{
			get
			{
				Coordinate[] array = new Coordinate[this.NumPoints];
				int num = -1;
				for (int i = 0; i < this._geometries.Length; i++)
				{
					Coordinate[] coordinates = this._geometries[i].Coordinates;
					for (int j = 0; j < coordinates.Length; j++)
					{
						num++;
						array[num] = coordinates[j];
					}
				}
				return array;
			}
		}

		public override double[] GetOrdinates(Ordinate ordinate)
		{
			if (this.IsEmpty)
			{
				return new double[0];
			}
			double[] array = new double[this.NumPoints];
			int num = 0;
			for (int i = 0; i < this.NumGeometries; i++)
			{
				double[] ordinates = this.GetGeometryN(i).GetOrdinates(ordinate);
				Array.Copy(ordinates, 0, array, num, ordinates.Length);
				num += ordinates.Length;
			}
			return array;
		}

		public override bool IsEmpty
		{
			get
			{
				for (int i = 0; i < this._geometries.Length; i++)
				{
					if (!this._geometries[i].IsEmpty)
					{
						return false;
					}
				}
				return true;
			}
		}

		public override Dimension Dimension
		{
			get
			{
				Dimension dimension = Dimension.False;
				for (int i = 0; i < this._geometries.Length; i++)
				{
					dimension = (Dimension)System.Math.Max((int)dimension, (int)this._geometries[i].Dimension);
				}
				return dimension;
			}
		}

		public override Dimension BoundaryDimension
		{
			get
			{
				Dimension dimension = Dimension.False;
				for (int i = 0; i < this._geometries.Length; i++)
				{
					dimension = (Dimension)System.Math.Max((int)dimension, (int)this._geometries[i].BoundaryDimension);
				}
				return dimension;
			}
		}

		public override int NumGeometries
		{
			get
			{
				return this._geometries.Length;
			}
		}

		public override IGeometry GetGeometryN(int n)
		{
			return this._geometries[n];
		}

		public IGeometry[] Geometries
		{
			get
			{
				return this._geometries;
			}
			protected set
			{
				this._geometries = value;
			}
		}

		public override int NumPoints
		{
			get
			{
				int num = 0;
				for (int i = 0; i < this._geometries.Length; i++)
				{
					num += this._geometries[i].NumPoints;
				}
				return num;
			}
		}

		public override string GeometryType
		{
			get
			{
				return "GeometryCollection";
			}
		}

		public override OgcGeometryType OgcGeometryType
		{
			get
			{
				return OgcGeometryType.GeometryCollection;
			}
		}

		public override IGeometry Boundary
		{
			get
			{
				base.CheckNotGeometryCollection(this);
				Assert.ShouldNeverReachHere();
				return null;
			}
		}

		public override double Area
		{
			get
			{
				double num = 0.0;
				for (int i = 0; i < this._geometries.Length; i++)
				{
					num += this._geometries[i].Area;
				}
				return num;
			}
		}

		public override double Length
		{
			get
			{
				double num = 0.0;
				for (int i = 0; i < this._geometries.Length; i++)
				{
					num += this._geometries[i].Length;
				}
				return num;
			}
		}

		public override bool EqualsExact(IGeometry other, double tolerance)
		{
			if (!this.IsEquivalentClass(other))
			{
				return false;
			}
			IGeometryCollection geometryCollection = (IGeometryCollection)other;
			if (this._geometries.Length != geometryCollection.Geometries.Length)
			{
				return false;
			}
			for (int i = 0; i < this._geometries.Length; i++)
			{
				if (!this._geometries[i].EqualsExact(geometryCollection.Geometries[i], tolerance))
				{
					return false;
				}
			}
			return true;
		}

		public override void Apply(ICoordinateFilter filter)
		{
			for (int i = 0; i < this._geometries.Length; i++)
			{
				this._geometries[i].Apply(filter);
			}
		}

		public override void Apply(ICoordinateSequenceFilter filter)
		{
			if (this._geometries.Length == 0)
			{
				return;
			}
			for (int i = 0; i < this._geometries.Length; i++)
			{
				((Geometry)this._geometries[i]).Apply(filter);
				if (filter.Done)
				{
					break;
				}
			}
			if (filter.GeometryChanged)
			{
				base.GeometryChanged();
			}
		}

		public override void Apply(IGeometryFilter filter)
		{
			filter.Filter(this);
			for (int i = 0; i < this._geometries.Length; i++)
			{
				this._geometries[i].Apply(filter);
			}
		}

		public override void Apply(IGeometryComponentFilter filter)
		{
			filter.Filter(this);
			for (int i = 0; i < this._geometries.Length; i++)
			{
				this._geometries[i].Apply(filter);
			}
		}

		public override object Clone()
		{
			GeometryCollection geometryCollection = (GeometryCollection)base.Clone();
			geometryCollection._geometries = new IGeometry[this._geometries.Length];
			for (int i = 0; i < this._geometries.Length; i++)
			{
				geometryCollection._geometries[i] = (IGeometry)this._geometries[i].Clone();
			}
			return geometryCollection;
		}

		public override void Normalize()
		{
			for (int i = 0; i < this._geometries.Length; i++)
			{
				this._geometries[i].Normalize();
			}
			Array.Sort<IGeometry>(this._geometries);
		}

		protected override Envelope ComputeEnvelopeInternal()
		{
			Envelope envelope = new Envelope();
			for (int i = 0; i < this._geometries.Length; i++)
			{
				envelope.ExpandToInclude(this._geometries[i].EnvelopeInternal);
			}
			return envelope;
		}

		protected internal override int CompareToSameClass(object o)
		{
			List<IGeometry> a = new List<IGeometry>(this._geometries);
			List<IGeometry> b = new List<IGeometry>(((GeometryCollection)o)._geometries);
			return Geometry.Compare(a, b);
		}

		protected internal override int CompareToSameClass(object o, IComparer<ICoordinateSequence> comp)
		{
			IGeometryCollection geometryCollection = (IGeometryCollection)o;
			int numGeometries = this.NumGeometries;
			int numGeometries2 = geometryCollection.NumGeometries;
			int num = 0;
			while (num < numGeometries && num < numGeometries2)
			{
				IGeometry geometryN = this.GetGeometryN(num);
				Assert.IsTrue(geometryN is Geometry);
				IGeometry geometryN2 = geometryCollection.GetGeometryN(num);
				int num2 = ((Geometry)geometryN).CompareToSameClass(geometryN2, comp);
				if (num2 != 0)
				{
					return num2;
				}
				num++;
			}
			if (num < numGeometries)
			{
				return 1;
			}
			if (num < numGeometries2)
			{
				return -1;
			}
			return 0;
		}

		public bool IsHomogeneous
		{
			get
			{
				IGeometry geometry = this.Geometries[0];
				for (int i = 1; i < this.Geometries.Length; i++)
				{
					if (geometry.GetType() != this.Geometries[i].GetType())
					{
						return false;
					}
				}
				return true;
			}
		}

		public IEnumerator<IGeometry> GetEnumerator()
		{
			return new GeometryCollectionEnumerator(this);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		public IGeometry this[int i]
		{
			get
			{
				return this._geometries[i];
			}
		}

		public override IGeometry Reverse()
		{
			IGeometry[] array = new IGeometry[this._geometries.Length];
			for (int i = 0; i < this._geometries.Length; i++)
			{
				array[i] = this._geometries[i].Reverse();
			}
			return base.Factory.CreateGeometryCollection(array);
		}

		public int Count
		{
			get
			{
				return this._geometries.Length;
			}
		}

		public static readonly IGeometryCollection Empty = Geometry.DefaultFactory.CreateGeometryCollection(null);

		private IGeometry[] _geometries;
	}
}
